#pragma once

#include <cstring>
#include <iostream>  
#include <functional>
 
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

#include "nocopy.hpp"
#include "Log.hxx"
#include "Common.hpp"
#include "MutiProcess.hxx"


const static int default_backlog = 5;


class TcpServer: public nocopy
{
    uint16_t _port;
    Log lg;
    int _listensock;
    bool _isRunning;
    std::function<struct sockaddr*(void*)> conv= [](void* addr){
        return (struct sockaddr*)addr;
    };
    public:
    TcpServer(uint16_t port)
    :_port(port)
    {

    }

    void Init()
    {
        //1.创建套接字

        //面向字节流的
        _listensock = socket(AF_INET,SOCK_STREAM,0);
        if(_listensock<0)
        {
            lg(Log::MsgLevel::Error,"create socket error ,ernno %d, %s",errno,strerror(errno));
            exit(Socket_error);
        }
        lg(Log::MsgLevel::Debug,"create socket success,%d\n",_listensock);


        int opt = 1;
        setsockopt(_listensock,SOL_SOCKET,SO_REUSEADDR | SO_REUSEPORT,&opt,sizeof(opt));

        //2.填充本地网络信息并行bind

        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        

        local.sin_family= AF_INET;
        local.sin_addr.s_addr = htonl(INADDR_ANY);
        local.sin_port = htons(_port);

        
        //进行bind
        if(bind(_listensock,conv((void*)&local),sizeof(local))!=0)
        {
            lg(Log::MsgLevel::Error,"bind error ,ernno %d, %s",errno,strerror(errno));
            exit(Bind_error);
        }
        lg(Log::Debug,"bind success\n");


        //Tcp 区别之一于Udp是需要监听的
        if(listen(_listensock,default_backlog)!=0)
        {
            lg(Log::MsgLevel::Error,"bind error ,ernno %d, %s",errno,strerror(errno));
        }
        lg(Log::Debug,"Listen socket sucess,sockfd:%d\n",_listensock);
    }    
    void Start()
    {
        //信号版子进程提供服务
        // signal(SIGCHLD,SIG_IGN);//linux里面，一旦进程设置了子进程信号忽略，那么子进程执行完就会自动释放


        //进程池版本
        //---------------------------
        std::function<void(int)> func =[this](int sockfd){
            close(this->_listensock);
            this->Service(sockfd);
            close(sockfd);
                
        };

        //多进程，进程池版本，可以一开始设立进程个数
        Processes pcs(func);

        //------------------------


        _isRunning =1;
        while(_isRunning)
        {
            //获取链接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listensock,conv(&peer),&len);
            if(sockfd<0)
            {
                lg(Log::MsgLevel::Warning,"accept socket error,errno code:%d,error string,%s\n",errno,strerror(errno));
                continue;
            }
            lg(Log::MsgLevel::Debug,"accept success\n");


            //如何给我们知道，TCP需要链接接受之后获取新的sockfd以进行通信
            //那么给多个用户提供服务呢？
            //选择多进程
            //这样每来一个链接，创建一个子进程


            //多进程提供服务版本1，孙子进程版
            //----------------------
            // pid_t cid = fork();
            // if(cid<0)
            // {
            //     close(sockfd);
            //     continue;
            // }
            // else if(cid ==0)
            // {
            //     //子进程
            //     close(_listensock);

            //     //这里，子进程再次创建一个子进程，自己就返回了，避免父进程一直阻塞
            //     if(fork()>0) 
            //     {
            //         //当前的子进程就退出
            //         exit(0);
            //     }
            //     else
            //     {
            //         //孙子进程变成孤儿进程。由系统领养，来负责管理回收
            //         //其孙子进程来执行这个任务
            //         //这样也就意味着如果没有出现问题，那么只有Clinet端退出之后，系统才会处理了
            //         Service(sockfd);
            //         close(sockfd);
            //         exit(0);
            //     }
            // }
            // else
            // {
            //     //父进程
            //     close(sockfd);
            //     pid_t return_id = waitpid(cid,nullptr,0);  
            //     if(return_id == cid)
            //     {
                    
            //     }
            // }

            //---------------------------------

            // //多进程版本2，信号版
            // pid_t id = fork();
            // if(id<0)
            // {
            //     close(sockfd);
            //     continue;
            // }
            // else if(id ==0 )
            // {
            //     //子进程
            //     close(_listensock);
            //     Service(sockfd);
            //     close(sockfd);
            //     exit(0);
            // }
            // else
            // {
            //     //父进程
            //     // close(sockfd);
            //     //nothing to do,只需要去获取新的链接即可
            // }
            //------------------------------

            //进程池版本
            //--------------
            pcs.PushTask(sockfd);//Pushback里面已经实现了closesockfd
            //-----------------------------




            //只有当前进程提供服务提供服务
            // Service(sockfd);
            // close(sockfd);



        }
    }

    
    void Service(int sockfd)
    {
        char sock_buffer[1024];
        while(1)
        {
            // dup2(sockfd,1);

            ssize_t n = read(sockfd,sock_buffer,sizeof(sock_buffer)-1);
            if(n>0)
            {
                sock_buffer[n] = 0;
                std::cout<<"Client Say#:"<<sock_buffer<<"\n";

                std::string echo_str = "Server return:";
                echo_str+= sock_buffer;
                write(sockfd,echo_str.c_str(),echo_str.size()+1);
            }
            else if(n==0)//读端读取到0，就是写端关闭了，在网络就是对端关闭了链接
            {
                
                lg(Log::Debug,"Client quit\n");
                break;
            }
            else
            {
                lg(Log::MsgLevel::Warning,"Read error,errno code:%d,error string,%s\n",errno,strerror(errno));
                break;
            }
        }
    }
};